package dgut.lgc.service;

import dgut.lgc.bean.DateRecord;
import dgut.lgc.bean.EpidemicSituation;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVRecord;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.io.*;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@EnableScheduling
public class AnalysisService {

    // 原数据
    private final ArrayList<EpidemicSituation> list = new ArrayList<>();

    // 获取原数据
    public String getData() {

        String uri = "https://gitee.com/wo_ming/COVID-19/raw/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv";

        RequestEntity<Void> requestEntity = RequestEntity.get(URI.create(uri))
                .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36")
                .header("Cookie", "user_locale=zh-CN; oschina_new_user=false; gr_user_id=15467a8a-ec98-4852-a935-ced9ad5f81f0; grwng_uid=66eabc60-a989-4010-a0d5-4b82f78b6fe1; Serve_State=true; remote_way=http; close_wechat_tour=true; visit-gitee-=1; remember_user_token=BAhbB1sGaQNzx0lJIiIkMmEkMTAkdmlmdTFkNzNWNXpvclZvRTRDR1dZdQY6BkVU--a12f0574be689b599d7387774b046324474aecd2; tz=Asia%2FShanghai; Hm_lvt_24f17767262929947cc3631f99bfd274=1588873085,1588928432,1588930401,1588934985; Hm_lpvt_24f17767262929947cc3631f99bfd274=1588936018; gitee-session-n=cGFZeU5XVVkyQTNzenZaTFpIN012ME9UNnJJY3dBd0U1cWlnTGNnZ2cyL0tad1hYeCtQV09wSWNieWdqTlUxcFNUMnNIOUJuWDJOeERtd1pOWGRHTE1zOHRJc2RyY0N4WElEdDRiak5zMitMV0NJQWEwNFdXQldzVDZkNU9oOVA3YWozUzV3NkhEVjdrSlo1NlpJREVUS29iZSthUEtBYUpEbjJPOVBEVWhuVlVVcVFCbUlhMDlsdm5ON1NRVmtFTEY1b3ZmTXdZOWZ4OXV6RHZTR2FnTUtLbEsreDVhdnc2d1A0NUE3dFNGMTFYSFlUWlM2L1ZwWkFRVUlsWkNxMnpSTVhDK1BCTEhaSWY0alZqVmVmQytFUSt2cFpxZUROaEtLMG9qSkxRYi9lR282WDVwMnhid25Yakl4QURVeXFIRzYrQno2bytUc0JQekdqcXRmTDQ4Y2JNa3o5WWN4NGNkazAwU05pZVVNWWZzYWp5Y0pISjVzTm1IaGVmNFQ2Z0VoZlFqS1RtaTZFRWp0L0V5eWNkNFZ0SWswY3lnMGxJa0FxMEt1dGhYSU9CUkVOem1TRDQ3dnFyREdSSVJmYy0tZDZkRUpnaFN3UVM0QmNkcXBKKzFtdz09--3faf527582b81cb1b15d3f7b7dfdc72916130575")
                .build();

        ResponseEntity<String> response = new RestTemplate().exchange(requestEntity, String.class);

        return response.getBody();
    }

    // 更新原数据
    @PostConstruct
    @Scheduled(cron = "0 0 1 * * *")
    public void upData() throws IOException {

        System.out.println("更新数据中...");

        String data = getData();

        assert data != null;
        // 清空旧数据
        list.clear();
        data = data.replaceAll("US","United States");
        Iterable<CSVRecord> records = CSVFormat
                .EXCEL
                .withHeader("Province/State", "Country/Region", "Lat", "Long")
                .parse(new InputStreamReader(new ByteArrayInputStream(data.getBytes()), StandardCharsets.UTF_8));

        for (CSVRecord record : records) {

            if ("Province/State".equals(record.get("Province/State"))) continue;

            EpidemicSituation es = new EpidemicSituation();
            es.setProvinceOrState(record.get("Province/State"));
            es.setCountryOrRegion(record.get("Country/Region"));
            es.setTotalPat(Integer.parseInt(record.get(record.size() - 1)));
            es.setCurrAdd(Integer.parseInt(record.get(record.size() - 1)) - Integer.parseInt(record.get(record.size() - 2)));

            DateRecord dateRecord = new DateRecord(2020, 1, 22);
            HashMap<String, Integer> map = new HashMap<>();
            for (int i = 4; i < record.size(); i++) {
                map.put(dateRecord.toString(), Integer.parseInt(record.get(i)));
                dateRecord.add(1);
            }
            es.setDayDetail(map);
            list.add(es);
        }
        System.out.println("更新成功");
    }

    // 封装累计确诊数据
    public String accumulateJson() {

        JSONObject accData = new JSONObject();
        JSONArray columns = new JSONArray();
        columns.add("日期");
        columns.add("累计确诊");
        accData.put("columns", columns);
        JSONArray rows = new JSONArray();

        accumulateData().forEach(s -> {
            JSONObject item = new JSONObject();
            item.put("日期", s.getKey());
            item.put("累计确诊", s.getValue());
            rows.add(item);
        });

        accData.put("rows", rows);

        return accData.toJSONString();

    }

    // 计算累计确诊
    public Stream<Map.Entry<String, Integer>> accumulateData() {

        return list.stream()
                .map(EpidemicSituation::getDayDetail)
                .reduce((m1, m2) -> {
                    HashMap<String, Integer> temp = new HashMap<>();
                    for (Map.Entry<String, Integer> entry : m1.entrySet()) {
                        if (m2.containsKey(entry.getKey())) {
                            temp.put(entry.getKey(), entry.getValue() + m2.get(entry.getKey()));
                        }
                    }
                    return temp;
                })
                .map(HashMap::entrySet)
                .stream()
                .flatMap(Collection::stream)
                .sorted(Map.Entry.comparingByKey());
    }

    // 计算每日新增
    public String dayAddData() {

        JSONObject dadData = new JSONObject();
        JSONArray columns = new JSONArray();
        columns.add("日期");
        columns.add("每日新增确诊");
        dadData.put("columns", columns);
        JSONArray rows = new JSONArray();

        int count = 0;
        for (var ac : accumulateData().collect(Collectors.toList())) {
            JSONObject item = new JSONObject();
            item.put("日期", ac.getKey());
            item.put("每日新增确诊", ac.getValue() - count);
            count = ac.getValue();
            rows.add(item);
        }

        dadData.put("rows",rows);

        return dadData.toJSONString();
    }

    // 计算总的数据
    public String totalData() {

        JSONObject totData = new JSONObject();

        // 累计确诊
        totData.put("total",list.stream()
                .map(EpidemicSituation::getTotalPat)
                .reduce(Integer::sum));

        // 较昨日新增
        totData.put("added",list.stream()
                .map(EpidemicSituation::getCurrAdd)
                .reduce(Integer::sum));

        // 最后更新日期
        totData.put("lastTime", list.stream()
                .map(e -> e.getDayDetail().keySet())
                .flatMap(Collection::stream)
                .max(Comparator.naturalOrder())
                .orElse("null"));

        return totData.toJSONString();
    }

    // 国家累计确诊人数
    public String countryOrRegionTotalNumber() {

        JSONObject ctnData = new JSONObject();
        JSONArray columns = new JSONArray();
        columns.add("位置");
        columns.add("累计确诊人数");
        ctnData.put("columns", columns);
        JSONArray rows = new JSONArray();

        list.stream()
                .collect(Collectors.groupingBy(EpidemicSituation::getCountryOrRegion,
                        Collectors.summingInt(EpidemicSituation::getTotalPat)))
                .forEach((key, value) -> {
                    JSONObject item = new JSONObject();
                    item.put("位置", key);
                    item.put("累计确诊人数", value);
                    rows.add(item);
                });

        ctnData.put("rows",rows);

        return ctnData.toJSONString();

    }

    // 返回原数据
    public List<EpidemicSituation> getList() {
        return list;
    }
}
